/*Nama File : CommandExecutor.cpp
  Pembuat	: Ni Made Satvika Iswari - 23512077/ Karina Novita Suryani - 23512187 
  tanggal 	: 1 November 2012
  */

#include "CommandExecutor.h"  
#include "../File/FileExp.h"
#include "CommandExecutorExp.h"

int CommandExecutor::execStatus = 0;

CommandExecutor::CommandExecutor() //ctor
{
	
}

CommandExecutor::CommandExecutor(const CommandExecutor& CE) //cctor
{
	curCalendar = CE.curCalendar;
	curCommandProcessor = CE.curCommandProcessor;
}

CommandExecutor::~CommandExecutor() //dtor
{
	curCalendar.DeleteCal();
	curCommandProcessor.Empty();
	CommandExecutor::execStatus = 0;
}

CommandExecutor& CommandExecutor::operator= (const CommandExecutor& CE) //operator=
{
	curCalendar.DeleteCal();
	curCommandProcessor.Empty();
	
	curCalendar = CE.curCalendar;
	curCommandProcessor = CE.curCommandProcessor;
}

//getter
CommandProcessor CommandExecutor::getCurCommandProcessor()
{
	return curCommandProcessor;
}

Calendar CommandExecutor::getCurCalendar()
/*mendapatkan current Calendar*/
{
	return curCalendar;
}

static int CommandExecutor::getExecStatus()
/*mendapatkan current status eksekusi*/
{
	return CommandExecutor::execStatus;
}

//setter
void CommandExecutor::setCurCommandProcessor(CommandProcessor cProcessor)
{
	curCommandProcessor = cProcessor;
}

void CommandExecutor::setCurCalendar(Calendar calendar)
/*I.S. sembarang */
/*F.S. curCalendar di set dengan inputan */
{
	curCalendar = calendar;
}

static void CommandExecutor::setExecStatus(int stat)
/*I.S. stat sudah valid sesuai dengan domain */
/*F.S. CommandExecutor::execStatus di set dengan inputan*/
{
	CommandExecutor::execStatus = stat;
}

//Operasi pada Calendar
void CommandExecutor::CreateCal(string calName)
/*I.S. sembarang */
/*F.S. mengosongkan curCalendar dan mengeset namanya menjadi nama yang diinputkan */
{
	curCalendar.DeleteCal();
	curCalendar.SetName(calName);
	CommandExecutor::execStatus = 1;
	cout<<"Calendar "<< calName<<" telah berhasil dibuat"<<endl;
}

void CommandExecutor::DeleteCal(string calName)
/*I.S. sembarang */
/*F.S. mengosongkan curCalendar dan mengeset namanya menjadi ""*/
{
	if (CommandExecutor::execStatus == 1){
	
		if (curCalendar.GetName() == calName){
			arrayUndoCalendar.push_back(curCalendar);
			curCalendar.DeleteCal();
			curCalendar.SetName("");
			cout<<"Calendar "<< calName<<" telah berhasil dihapus"<<endl;
		} else {
			throw(CommandExecutorExp(WRONG_CAL_NAME));
		}
	} else {
		throw(CommandExecutorExp(NO_CALENDAR));
	}
	
}

void CommandExecutor::SaveCal(string fileName)
/*I.S. curCalendar mungkin kosong*/
/*F.S. menyimpan isi curCalendar ke dalam file */
{
	if (CommandExecutor::execStatus == 1){
	
		if (IsFileExtValid(fileName, "cal")){
			//string nama = curCalendar.GetPath() + fileName;
			curCalendar.SaveFile(fileName);
			cout<<"Calendar "<< curCalendar.GetName() <<" telah berhasil disimpan ke "<<fileName<<endl;
		}else {
			throw(FileExp (ERROR_FORMAT));
		}
	} else {
		throw(CommandExecutorExp(NO_CALENDAR));
	}
	
	
}

void CommandExecutor::LoadCal(string fileName)
/*I.S. curCalendar mungkin sudah terisi */
/*F.S. mengosongkan curCalendar lalu me-load isi file ke dalam kalender*/
{
	if (IsFileExtValid(fileName, "cal")){
		//string nama = curCalendar.GetPath() + fileName;
		curCalendar.ReadFile(fileName);
		CommandExecutor::execStatus = 1;
		cout<<"Calendar "<< curCalendar.GetName() <<" telah berhasil dari "<<fileName<<endl;
	}else {
		throw(FileExp (ERROR_FORMAT));
	}
}

bool CommandExecutor::IsFileExtValid(string FileName, string Ext)
/* Parameter extention tidak mengandung titik "." */
/* Mengembalikan true jika file extention sesuai dengan yang telah ditentukan */
{
	string delimiters = ".";
	size_t current;
	size_t next = -1;
	vector<string> cont;
	
	/* Melakukan spliting nama file dengan delimiter ".", kemudian menyimpannya dalam container vector cont*/
	do{
		current = next + 1;
		next = FileName.find_first_of( delimiters, current );
		cont.push_back(FileName.substr( current, next - current ));
	}while (next != string::npos);
	
	/* Jika cont terakhir sesuai dengan Ext return true, else false */
	if (cont[cont.size() - 1] == Ext){
		return true;
	}else{
		return false;
	}
}

void CommandExecutor::SortCal(string calName)
/*I.S. curCalendar mungkin kosong*/
/*F.S. mengurutkan Calendar berdasarkan tanggal event*/
{
	if (CommandExecutor::execStatus == 1){
	
		if (curCalendar.GetName() == calName){
			arrayUndoCalendar.push_back(curCalendar);
			curCalendar.SortCal();
			cout<<"Calendar "<< calName <<" telah berhasil diurut"<<endl;

		} else {
			throw(CommandExecutorExp(WRONG_CAL_NAME));
		}
	} else {
		throw(CommandExecutorExp(NO_CALENDAR));
	}
	
}

void CommandExecutor::AddCalEvent(string calName,int eventNo)
/*I.S. sembarang*/
/*F.S. menambahkan event pada kalender dengan event no dan nama Calendar yg sesuai*/
{
	if (CommandExecutor::execStatus == 1){
	
		if (curCalendar.GetName() == calName){
			arrayUndoCalendar.push_back(curCalendar);
			Event E;
			E.BacaEvent(eventNo);
			curCalendar.AddEvent(E);
			
		} else {
			throw(CommandExecutorExp(WRONG_CAL_NAME));
		}
	} else {
		throw(CommandExecutorExp(NO_CALENDAR));
	}	
	
}

void CommandExecutor::DeleteCalEvent(string calName,int eventNo)
/*I.S. curCalendar mungkin kosong, event yang ingin dihapus mungkin tidk ada di Calendar*/
/*F.S. menghapus event pada Calendar dengan nama Calendar dan event no yng sesuai*/
{
	if (CommandExecutor::execStatus == 1){
	
		if (curCalendar.GetName() == calName){
			arrayUndoCalendar.push_back(curCalendar);
			curCalendar.DelEvent(eventNo);
		
		} else {
			throw(CommandExecutorExp(WRONG_CAL_NAME));
		}
	} else {
		throw(CommandExecutorExp(NO_CALENDAR));
	}
	
}

//Operasi pada Command
void CommandExecutor::EmptyCommand()
/*I.S. daftar command mungkin kosong */
/*F.S. mengosongkan memori yang menyimpan daftar command yang valid yang pernah diinputkan user*/
{
	if (!curCommandProcessor.IsEmpty()){
		curCommandProcessor.Empty();
	} 
}

void CommandExecutor::SaveCommand(string FileName)
/*I.S. daftar command mungkin kosong */
/*F.S. menyimpan hanya daftar command yang valid yang pernah diinputkan user */
/* Ekstensi nama file yang digunakan harus sesuai, yaitu ".log" */
{
	if (IsFileExtValid(FileName, "log")){
		curCommandProcessor.SaveFile(FileName);
	} else {
		throw(FileExp (ERROR_FORMAT));
	}
}

void CommandExecutor::DisplayCommand()
/*I.S. daftar referensi valid mungkin kosong */
/*F.S. menampilkan referensi command valid yang ada pada filename yang diinputkan*/
{
	curCommandProcessor.DisplayRefCommand();
}

void CommandExecutor::UndoCommand(int N)
/*I.S. sembarang */
/*F.S. mengembalikan curCalender ke state curCalender pada aksi sebelumnya sebanyak n kali */
{
	int i = 0;
	
	while((i < N) && (!arrayUndoCalendar.empty())){
		arrayRedoCalendar.push_back(curCalendar);
		curCalendar = arrayUndoCalendar.back();
		arrayUndoCalendar.pop_back();
		i++;
	}
}

void CommandExecutor::RedoCommand(int N)
/*I.S. telah melakukan undi */
/*F.S. mengembalikan curCalender ke state curCalender pada sebelum undo sebanyak n kali*/
{
	int i = 0;
	
	while((i < N) && (!arrayRedoCalendar.empty())){
		arrayUndoCalendar.push_back(curCalendar);
		curCalendar = arrayRedoCalendar.back();
		arrayRedoCalendar.pop_back();
		i++;
	}
}

//Operasi pada aplikasi
void CommandExecutor::Quit()
/*I.S. sembarang*/
/*F.S. CommandExecutor::execStatus = 99 */
{
	CommandExecutor::execStatus = 99;
}

//exekusi command
void CommandExecutor::Exec(string userCommand)
/*I.S. sembarang */
/*F.S. memarsing string perintah user, lalu mengeksekusi perintah user*/
{
	
	//membuat command
	DateTime tStartExec;
	srand((unsigned)time(0));
	int durSecond;
	durSecond = (rand()%100)+1;
	
	command uCommand(userCommand,durSecond ,tStartExec);
	
	
	if (curCommandProcessor.AddCommand(uCommand)){
		if (!uCommand.getArgument(0).compare(CommandProcessor::RefCommand[0].getArgument(0))){
			CreateCal(uCommand.getArgument(1));
		
		} else if (!uCommand.getArgument(0).compare(CommandProcessor::RefCommand[1].getArgument(0))){
			DeleteCal(uCommand.getArgument(1));
			
		} else if (!uCommand.getArgument(0).compare(CommandProcessor::RefCommand[2].getArgument(0))){
			SortCal(uCommand.getArgument(1));
		
		} else if (!uCommand.getArgument(0).compare(CommandProcessor::RefCommand[3].getArgument(0))){
			try{
				SaveCal(uCommand.getArgument(1));
			}catch (FileExp& f){
				f.DisplayMsg();
			}
		} else if (!uCommand.getArgument(0).compare(CommandProcessor::RefCommand[4].getArgument(0))){
			try{
				LoadCal(uCommand.getArgument(1));
			}catch (FileExp& f){
				f.DisplayMsg();
			}
		} else if (!uCommand.getArgument(0).compare(CommandProcessor::RefCommand[5].getArgument(0))){
			EmptyCommand();
		
		} else if (!uCommand.getArgument(0).compare(CommandProcessor::RefCommand[6].getArgument(0))){
			try{
				SaveCommand(uCommand.getArgument(1));
			}catch (FileExp& f){
				f.DisplayMsg();
			}
		} else if (!uCommand.getArgument(0).compare(CommandProcessor::RefCommand[7].getArgument(0))){
			DisplayCommand();
		
		} else if (!uCommand.getArgument(0).compare(CommandProcessor::RefCommand[8].getArgument(0))){
			
			stringstream ss(uCommand.getArgument(2));
			int eventNo;
			
			if(ss >> eventNo){
				AddCalEvent(uCommand.getArgument(1),eventNo);
			}else{
				throw(CommandExecutorExp(ARG_NOT_INT));
			}
			
		
		} else if (!uCommand.getArgument(0).compare(CommandProcessor::RefCommand[9].getArgument(0))){
			stringstream ss(uCommand.getArgument(2));
			int eventNo;
			
			if(ss >> eventNo){
				DeleteCalEvent(uCommand.getArgument(1),eventNo);
			}else{
				throw(CommandExecutorExp(ARG_NOT_INT));
			}
		
		} else if (!uCommand.getArgument(0).compare(CommandProcessor::RefCommand[11].getArgument(0))){
			stringstream ss(uCommand.getArgument(1));
			int countUndo;
			
			if(ss >> countUndo){
				UndoCommand(countUndo);
			}else{
				throw(CommandExecutorExp(ARG_NOT_INT));
			}
		
		} else if (!uCommand.getArgument(0).compare(CommandProcessor::RefCommand[10].getArgument(0))){
			stringstream ss(uCommand.getArgument(1));
			int countRedo;
			
			if(ss >> countRedo){
				RedoCommand(countRedo);
			}else{
				throw(CommandExecutorExp(ARG_NOT_INT));
			}
		
		} else if (!uCommand.getArgument(0).compare(CommandProcessor::RefCommand[12].getArgument(0))){
			Quit();
		
		}
		
		
	
	} else {
		throw(CommandExecutorExp(COM_NOT_VALID));
	}
}